package cvgenerator.backend;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 *
 * @author Lukas
 */
public class Cv {

    private String name;
    private Address address;
    private String phone;
    private String email;
    private String bDay;
    private Long id;
    private List<WorkExperience> workExperience;
    private List<School> schools;
    private List<Language> languages;
    private List<String> interests;
    private List<String> skills;

    public Cv() {
        workExperience = new ArrayList<WorkExperience>();
        schools = new ArrayList<School>();
        interests = new ArrayList<String>();
        skills = new ArrayList<String>();
        languages = new ArrayList<Language>();
    }

    /**
     * This function write into file, xml document with data from local variables.
     * creating structure that is needed for xmlt transformation
     * @param file 
     */
    public void saveToFile(File file) {

        try {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            Document doc = docBuilder.newDocument();
            Element rootElement = doc.createElement("cv");
            doc.appendChild(rootElement);
            
            Attr id = doc.createAttribute("id");
            String fileName = file.getName();
            String[] nameParsed = fileName.split("[.]");
            id.setValue(nameParsed[0]);
            rootElement.setAttributeNode(id);

            Element nameOfPer = doc.createElement("name");
            nameOfPer.appendChild(doc.createTextNode(this.name));
            rootElement.appendChild(nameOfPer);

            Element adr = doc.createElement("address");
            rootElement.appendChild(adr);

            Element street = doc.createElement("street");
            street.appendChild(doc.createTextNode(address.getStreet()));
            adr.appendChild(street);

            Element streetNumber = doc.createElement("streetnumber");
            streetNumber.appendChild(doc.createTextNode(address.getStreetNumber()));
            adr.appendChild(streetNumber);

            Element postNumber = doc.createElement("postnumber");
            postNumber.appendChild(doc.createTextNode(address.getPostNumber()));
            adr.appendChild(postNumber);

            Element city = doc.createElement("city");
            city.appendChild(doc.createTextNode(address.getCity()));
            adr.appendChild(city);

            Element country = doc.createElement("country");
            country.appendChild(doc.createTextNode(address.getCountry()));
            adr.appendChild(country);

            Element phoneN = doc.createElement("phone");
            phoneN.appendChild(doc.createTextNode(this.phone));
            rootElement.appendChild(phoneN);

            Element mail = doc.createElement("email");
            mail.appendChild(doc.createTextNode(this.email));
            rootElement.appendChild(mail);

            Element birthday = doc.createElement("birthday");
            birthday.appendChild(doc.createTextNode(this.bDay));
            rootElement.appendChild(birthday);

            Element workExperiences = doc.createElement("workexperiences");
            rootElement.appendChild(workExperiences);
            
            
            for (WorkExperience workExperience1 : workExperience) {
                Element work = doc.createElement("work");
                workExperiences.appendChild(work);
                
                Element from = doc.createElement("from");
                from.appendChild(doc.createTextNode(workExperience1.getFrom()));
                work.appendChild(from);
                
                Element to = doc.createElement("to");
                to.appendChild(doc.createTextNode(workExperience1.getTo()));
                work.appendChild(to);

                Element company = doc.createElement("company");
                company.appendChild(doc.createTextNode(workExperience1.getCompany()));
                work.appendChild(company);

                Element position = doc.createElement("position");
                position.appendChild(doc.createTextNode(workExperience1.getPosition()));
                work.appendChild(position);
                if (workExperience1.getNote() != null) {
                    Element note = doc.createElement("note");
                    note.appendChild(doc.createTextNode(workExperience1.getNote()));
                    work.appendChild(note);
                }
            }

            Element education = doc.createElement("education");
            rootElement.appendChild(education);

            for (School school1 : schools) {
                Element school = doc.createElement("school");
                education.appendChild(school);

                Element from = doc.createElement("from");
                from.appendChild(doc.createTextNode(school1.getFrom()));
                school.appendChild(from);

                Element to = doc.createElement("to");
                to.appendChild(doc.createTextNode(school1.getTo()));
                school.appendChild(to);

                Element schoolName = doc.createElement("name");
                schoolName.appendChild(doc.createTextNode(school1.getName()));
                school.appendChild(schoolName);

                Element field = doc.createElement("field");
                field.appendChild(doc.createTextNode(school1.getField()));
                school.appendChild(field);
                
                if (school1.getDegree() != null) {
                    Element degree = doc.createElement("degree");
                    degree.appendChild(doc.createTextNode(school1.getDegree()));
                    school.appendChild(degree);
                }
                
                if (school1.getNote() != null) {
                    Element note = doc.createElement("note");
                    note.appendChild(doc.createTextNode(school1.getNote()));
                    school.appendChild(note);
                }
            }
            Element lngs = doc.createElement("languages");
            rootElement.appendChild(lngs);

            for (Language lng : languages) {

                Element language = doc.createElement("language");
                lngs.appendChild(language);

                Element langName = doc.createElement("name");
                langName.appendChild(doc.createTextNode(lng.getName()));
                language.appendChild(langName);

                Element level = doc.createElement("level");
                level.appendChild(doc.createTextNode(lng.getLevel()));
                language.appendChild(level);
                
                if (lng.getCertificate() != null) {
                    Element certificate = doc.createElement("certificate");
                    certificate.appendChild(doc.createTextNode(lng.getCertificate()));
                    language.appendChild(certificate);
                }
            }

            Element intrs = doc.createElement("interests");
            rootElement.appendChild(intrs);

            for (String intr : interests) {

                Element interest = doc.createElement("interest");
                interest.appendChild(doc.createTextNode(intr));
                intrs.appendChild(interest);
            }

            Element allSkills = doc.createElement("skills");
            rootElement.appendChild(allSkills);
            
            for (String skill : skills) {

                Element skillElem = doc.createElement("addtionalskill");
                skillElem.appendChild(doc.createTextNode(skill));
                allSkills.appendChild(skillElem);
            }
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer();
            DOMSource source = new DOMSource(doc);
            StreamResult result = new StreamResult(file);

            transformer.transform(source, result);
            
        } catch (ParserConfigurationException e) {
            Logger.getLogger(Cv.class.getName()).log(Level.SEVERE, null, e);
        } catch (TransformerException ex) {
            Logger.getLogger(Cv.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    /**
     * this function read from saved xml file, parsing it and returning new CV with filled parameters from files.
     * @param file
     * @return CV 
     */
    public static Cv loadFromFile(File file) {
        String nameOfFile = file.getName();
        String[] ids = nameOfFile.split("[.]");
        String cvId = ids[0];
        
        Document doc;
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder;
        Cv result = new Cv();
        result.setId(Long.parseLong(cvId));
        
        try {
            builder = factory.newDocumentBuilder();
            doc = builder.parse(file.toURI().toString());
            
            NodeList wExperiences = doc.getElementsByTagName("work");
            NodeList education = doc.getElementsByTagName("school");
            NodeList allLanguages = doc.getElementsByTagName("language");
            NodeList allInterests = doc.getElementsByTagName("interest");
            NodeList allSkills = doc.getElementsByTagName("addtionalskill");
            
            NodeList rootChildren = doc.getDocumentElement().getChildNodes();
            
            
            for(int i = 0; i<rootChildren.getLength(); i++){
                if(rootChildren.item(i).getNodeName().equals("name")){
                    result.name = rootChildren.item(i).getTextContent();
                }
                if(rootChildren.item(i).getNodeName().equals("phone")){
                    result.phone = rootChildren.item(i).getTextContent();
                }
                if(rootChildren.item(i).getNodeName().equals("phone")){
                    result.phone = rootChildren.item(i).getTextContent();
                }
                if(rootChildren.item(i).getNodeName().equals("email")){
                    result.email = rootChildren.item(i).getTextContent();
                }
                if(rootChildren.item(i).getNodeName().equals("birthday")){
                    result.bDay = rootChildren.item(i).getTextContent();
                }
                
            }
            NodeList addressNodes = doc.getElementsByTagName("address");
            result.address =  Cv.parseAddress(addressNodes);
            result.workExperience = Cv.parseExperience(wExperiences);
            result.schools = Cv.parseSchool(education);
            result.languages = Cv.parseLanguages(allLanguages);
            
            result.interests = Cv.parseListOfStrings(allInterests);
            result.skills = Cv.parseListOfStrings(allSkills);
            
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(Cv.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(Cv.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Cv.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return result;
    }
    
    private static List<String> parseListOfStrings(NodeList nl){
        List<String> result = new ArrayList<String>();
            for(int i = 0; i < nl.getLength(); i++){
                String s = nl.item(i).getTextContent();
                        
                result.add(s);
            }
            return result;
    }
    
    private static List<Language> parseLanguages(NodeList nl) {
        List<Language> result = new ArrayList<Language>();

        for (int i = 0; i < nl.getLength(); i++) {

            NodeList nodelist = nl.item(i).getChildNodes();
            Language lang = new Language();
            for (int j = 0; j < nodelist.getLength(); j++) {
                
                if(nodelist.item(j).getNodeName().equals("name")){
                    lang.setName(nodelist.item(j).getTextContent());
                }
                if(nodelist.item(j).getNodeName().equals("level")){
                    lang.setLevel(nodelist.item(j).getTextContent());
                }

                try {
                    if(nodelist.item(j).getNodeName().equals("certificate")){
                        lang.setCertificate(nodelist.item(j).getTextContent());
                    }   
                } catch (IndexOutOfBoundsException e) {
                    lang.setCertificate(null);
                }catch (NullPointerException ex){
                    lang.setCertificate(null);
                }
            }
            result.add(lang);
        }
        return result;
    }
    
    private static List<School> parseSchool(NodeList nl) {
        List<School> result = new ArrayList<School>();
        
        for (int j = 0; j < nl.getLength(); j++) {
            NodeList nodelist = nl.item(j).getChildNodes();
            School s = new School();
            
            for (int i = 0; i < nodelist.getLength(); i++) {
                
                if(nodelist.item(i).getNodeName().equals("from")){
                    s.setFrom(nodelist.item(i).getTextContent());
                }
                if(nodelist.item(i).getNodeName().equals("to")){
                    s.setTo(nodelist.item(i).getTextContent());
                }
                if(nodelist.item(i).getNodeName().equals("name")){
                    s.setName(nodelist.item(i).getTextContent());
                }
                if(nodelist.item(i).getNodeName().equals("field")){
                    s.setField(nodelist.item(i).getTextContent());
                }
                
                try {
                    if(nodelist.item(i).getNodeName().equals("degree")){
                        s.setDegree(nodelist.item(i).getTextContent());
                    }
                    if(nodelist.item(i).getNodeName().equals("note")){
                        s.setNote(nodelist.item(i).getTextContent());
                    }
                } catch (IndexOutOfBoundsException e) {
                    s.setDegree(null);
                    s.setNote(null);
                }catch(NullPointerException e){
                    if(s.getDegree() == null){
                        s.setDegree(null);
                    }
                    if(s.getNote() == null){
                        s.setNote(null);
                    }
                }
            }
            result.add(s);
        }
        return result;
    }
    
    

    private static List<WorkExperience> parseExperience(NodeList nl) {
        
        if (nl.getLength() <= 0) {
            return null;
        }
        
        List<WorkExperience> result = new ArrayList<WorkExperience>();
        for (int j = 0; j < nl.getLength(); j++) {
            
            NodeList nodelist = nl.item(j).getChildNodes();
            WorkExperience exp = new WorkExperience();
            
            for (int i = 0; i < nodelist.getLength(); i++) {
                
                if(nodelist.item(i).getNodeName().equals("from")){
                    exp.setFrom(nodelist.item(i).getTextContent());
                }
                if(nodelist.item(i).getNodeName().equals("to")){
                    exp.setTo(nodelist.item(i).getTextContent());
                }
                if(nodelist.item(i).getNodeName().equals("company")){
                    exp.setCompany(nodelist.item(i).getTextContent());
                }
                if(nodelist.item(i).getNodeName().equals("position")){
                    exp.setPosition(nodelist.item(i).getTextContent());
                }
                
                try {

                    if(nodelist.item(i).getNodeName().equals("note")){
                        exp.setNote(nodelist.item(i).getTextContent());
                    }
                    
                } catch (IndexOutOfBoundsException e) {
                    exp.setNote(null);
                } catch (NullPointerException ex) {
                    exp.setNote(null);
                }
            }
            result.add(exp);
        }
        return result;
    }
    private static Address parseAddress(NodeList nl){
        Address result = new Address();
        
        NodeList addressList = nl.item(0).getChildNodes();
        
        for(int i =0; i<addressList.getLength();i++){
            if(addressList.item(i).getNodeName().equals("street")){
                result.setStreet(addressList.item(i).getTextContent());
            }
            if(addressList.item(i).getNodeName().equals("streetnumber")){
                result.setStreetNumber(addressList.item(i).getTextContent());
            }
            if(addressList.item(i).getNodeName().equals("postnumber")){
                result.setPostNumber(addressList.item(i).getTextContent());
            }
            if(addressList.item(i).getNodeName().equals("city")){
                result.setCity(addressList.item(i).getTextContent());
            }
            if(addressList.item(i).getNodeName().equals("country")){
                result.setCountry(addressList.item(i).getTextContent());
            }
        }
        
        return result;
    }
    
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public List<WorkExperience> getWorkExperience() {
        return workExperience;
    }

    public void setWorkExperience(List<WorkExperience> workExperience) {
        this.workExperience = workExperience;
    }

    public List<School> getSchools() {
        return schools;
    }

    public void setSchools(List<School> schools) {
        this.schools = schools;
    }

    public List<Language> getLanguages() {
        return languages;
    }

    public void setLanguages(List<Language> languages) {
        this.languages = languages;
    }

    public List<String> getInterests() {
        return interests;
    }

    public void setInterests(List<String> interests) {
        this.interests = interests;
    }

    public List<String> getSkills() {
        return skills;
    }

    public void setSkills(List<String> skills) {
        this.skills = skills;
    }

    public String getbDay() {
        return bDay;
    }

    public void setbDay(String bDay) {
        this.bDay = bDay;
    }
}
